/**
 *
 */
package com.ybkj.daijia.server;

import com.ybkj.daijia.serverUtils.RegExpValidatorUtils;
import com.ybkj.daijia.Setting;
import com.ybkj.daijia.serverUtils.SettingUtils;
import com.ybkj.daijia.common.Principal;
import com.ybkj.daijia.common.RandomString;
import com.ybkj.daijia.server.event.model.OperationLogEvent;
import com.ybkj.daijia.server.exception.LoginVcodeErrorException;
import com.ybkj.daijia.server.mapper.RoleAuthorityMapper;
import com.ybkj.daijia.server.model.Admin;
import com.ybkj.daijia.server.model.Company;
import com.ybkj.daijia.server.model.Role;
import com.ybkj.daijia.server.model.RoleAuthority;
import com.ybkj.daijia.server.service.AdminService;
import com.ybkj.daijia.server.service.CompanyService;
import com.ybkj.daijia.server.service.RoleService;
import com.ybkj.daijia.server.service.SmsService;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import nl.captcha.Captcha;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.UnsupportedTokenException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 用户认证
 *
 * @author Shine
 *
 */
public class AuthenticationRealm extends AuthorizingRealm {

    @Autowired
    private AdminService adminService;

    @Autowired
    private SettingUtils settingUtils;

    @Autowired
    private CompanyService companyService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RoleAuthorityMapper roleAuthorityMapper;

    @Autowired
    private SmsService smsService;

    @PostConstruct
    public void initCredentialsMatcher() {
        HashedCredentialsMatcher cm = new HashedCredentialsMatcher(
            Sha256Hash.ALGORITHM_NAME);
        setCredentialsMatcher(cm);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache
     * .shiro.subject.PrincipalCollection)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {

        Principal principal = (Principal) pc.fromRealm(getName()).iterator().next();

        List<Role> roles = roleService.findByAdmin(principal.getId());

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        if (!CollectionUtils.isEmpty(roles)) {
            for (Role role : roles) {

                List<RoleAuthority> roleAuthorities = roleAuthorityMapper
                    .selectByRoleId(role.getId());

                if (!CollectionUtils.isEmpty(roleAuthorities)) {

                    for (RoleAuthority roleAuthority : roleAuthorities) {
                        authorizationInfo.addStringPermission(roleAuthority.getAuthority());
                    }

                    //authorizationInfo.addStringPermissions(role.getAuthorities());
                }
            }
        }

        return authorizationInfo;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org
     * .apache.shiro.authc.AuthenticationToken)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
        AuthenticationToken token) throws AuthenticationException {

        com.ybkj.daijia.server.AuthenticationToken authenticationToken = (com.ybkj.daijia.server.AuthenticationToken) token;

        Principal temp_principal = new Principal(0L, authenticationToken.getUsername());
        temp_principal.setHost(authenticationToken.getIPAddress());

        ApplicationEventMulticaster applicationEventMulticaster = Config
            .getWac().getBean(ApplicationEventMulticaster.class);

        // 验证验证码
        if (!authenticationToken.getCaptcha().isCorrect(authenticationToken.getAnswer())) {

            String detail = "【%s】登录系统，验证码错误，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new UnsupportedTokenException();
        }

        // 验证用户
        String username = authenticationToken.getUsername();
        String password = new String(authenticationToken.getPassword());

        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { // 验证用户名密码是否为空

            String detail = "【%s】登录系统，用户名/密码为空，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new UnknownAccountException();
        }

        if (username.length() > 30 || password.length() > 50) { // 三级等保 数据过长

            String detail = "【%s】登录系统，用户名/密码过长，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new UnknownAccountException();
        }

        Admin admin = adminService.findByUsername(username);

        if (null == admin) { // 验证用户是否存在

            String detail = "【%s】登录系统，用户名错误，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new UnknownAccountException();
        }
        if (admin.getIsLocked()) { // 判断管理员是否禁用

            String detail = "【%s】登录系统，用户被禁用，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new DisabledAccountException();
        }
        if (!RegExpValidatorUtils.isIP(authenticationToken.getIPAddress())) {

            String detail = "【%s】登录系统，非法IP，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new DisabledAccountException();
        }

        if (admin.isPhoneLogin()) {
            if (StringUtils.isNotBlank(admin.getPhone())) {
                if (StringUtils.isBlank(authenticationToken.getVcode())) {
                    String detail = "【%s】登录系统，校验码为空，后台登录。";
                    OperationLogEvent operationLogEvent = new OperationLogEvent(
                        temp_principal, detail);
                    applicationEventMulticaster.multicastEvent(operationLogEvent);

                    clearCaptcha();

                    throw new LoginVcodeErrorException();
                }
                if (!admin.getVcode().equals(authenticationToken.getVcode())) {
                    String detail = "【%s】登录系统，校验码错误，后台登录。";
                    OperationLogEvent operationLogEvent = new OperationLogEvent(
                        temp_principal, detail);
                    applicationEventMulticaster.multicastEvent(operationLogEvent);

                    clearCaptcha();

                    throw new LoginVcodeErrorException();
                }
                long time = (System.currentTimeMillis() - admin.getExpired().getTime()) / 1000;//多少秒
                if (time >= 60 * 30) {//30分
                    String detail = "【%s】登录系统，校验码已失效，后台登录。";
                    OperationLogEvent operationLogEvent = new OperationLogEvent(
                        temp_principal, detail);
                    applicationEventMulticaster.multicastEvent(operationLogEvent);

                    clearCaptcha();

                    throw new LoginVcodeErrorException();
                }
            }
        }

        Sha256Hash hash = new Sha256Hash(password, Admin.SALT_KEY);

        if (admin.getPassword().equals(hash.toBase64())) { // 密码匹配

            Setting setting = settingUtils.get();

            StringBuilder sb = new StringBuilder();
            sb.append("secKey").append("=").append(setting.getSecKey());

//			JSONCheckStatus jcs = null;
//			try {
//				jcs = HttpClientUtil.checkLogin("http://dj.easymin.com/api/rest/app/driverapp/checkStatus" + "?"
//						+ sb.toString());
//			} catch (Exception e) {
//				// throw new LoginCheckErrorException();
//			}

            String virtualMessage = null;
            String smsMessage = null;
//
//			if (null != jcs && jcs.isSuccess()) {
//				if (!jcs.getStatus().equals("running")) {
//					throw new DebtsErrorException(jcs.getStatus(),
//							jcs.getPuaseTime(), jcs.getFee(), jcs.getMemo());
//				}
//				String nowStr = DateFormatUtils
//						.format(new Date(), "yyyy-MM-dd");
//				SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
//
//				try {
//					Date nowTime = dateFormat.parse(nowStr);
//					if ((jcs.getPuaseTimeStamp() - nowTime.getTime())
//							/ (1000 * 60 * 60 * 24) <= 5) {
//						virtualMessage = jcs.getMemo();
//					}
//				} catch (ParseException e) {
//
//				}
//			}

            // 短信条数

            try {
                Long smsCount = smsService.querySmsAppBalance();
                if (smsCount <= 200) {
                    smsMessage = "您的106短信已少于200条，为了不影响客户微信、APP下单，请及时充值！";
                }
            } catch (Exception e) {

            }

            StringBuilder loginTokenBuilder = new StringBuilder();
            loginTokenBuilder.append(RandomString.randomString(12))
                .append(String.valueOf(System.currentTimeMillis()));
            Sha256Hash loginTokenHash = new Sha256Hash(loginTokenBuilder.toString());
            String loginToken = loginTokenHash.toBase64();

            admin.setLoginToken(loginToken);
            admin.setLoginFailed(0);
            adminService.updateByPrimaryKey(admin);

            Company company = companyService.findOne(admin.getCompanyId());

            Principal principal = new Principal(admin.getId(), admin.getUsername());
            principal.setLoginToken(loginToken);

            if (null != company) {
                principal.setCompanyName(company.getCompanyName());
                principal.setCompanyAbbreviation(company.getAbbreviation());
                principal.setCompanyId(company.getId());
                principal.setCompanyType(company.isCompanyType());
            }

            principal.setHost(authenticationToken.getIPAddress());
            /** 去掉页面 5月30日系统到期提示*/
//			principal.setVirtualMessage(virtualMessage);
            principal.setSmsMessage(smsMessage);

            String detail = "【%s】登录了系统，登录成功，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            return new SimpleAuthenticationInfo(principal, Base64.decode(admin.getPassword()),
                hash.getSalt(), getName());

        } else {

            String detail = "【%s】登录系统，密码错误，后台登录。";
            OperationLogEvent operationLogEvent = new OperationLogEvent(
                temp_principal, detail);
            applicationEventMulticaster.multicastEvent(operationLogEvent);

            clearCaptcha();

            throw new IncorrectCredentialsException();
        }

    }

    private void clearCaptcha() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        request.getSession().removeAttribute(Captcha.NAME);
    }


}
